/*
 * Middleware
 * Copyright (C) 2010/11
 * Riccardo Pulvirenti, Giuseppe Ravidà, Andrea Tino
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANDABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses
 */

/*!
 * File: worker.hpp
 */

#ifndef _WORKER_HPP_
#define _WORKER_HPP_

#include <iostream>
#include <string>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/thread/mutex.hpp>

#include "runner.hpp"
#include "worker_descriptor.hpp"
#include "task_descriptor.hpp"
#include "synqueue.cpp"

//-----------------------------------------------------------------------------
// Enum, struct, aliases
namespace middleware {
typedef SynQueue<TaskDescriptor, 25> TaskSynQueue;
/*!
 * Network configuration.
 */
typedef struct {
	/* We should provide std::string worker_port_toman_bind but this address
	 * of binding is provided by Address, it is for the communication to
	 * manager */
	std::string worker_ip_todisc; /* IP to discovery */
	std::string worker_port_todisc; /* Port to discovery */
} WorkerConfig;
}
//-----------------------------------------------------------------------------
// Constants
namespace middleware {
/*!
 * Min port to which the Worker will listen for incoming tasks.
 */
const unsigned int kWorkerMinManPort = 1051;
/*!
 * Limiting port number to 2^16 - 1.
 */
const unsigned int kWorkerMaxManPort = 65536 - 1;
/*!
 * Period of time to check worker conditions and, if something changed, send
 * this new status to discovery.
 */
const unsigned int kWorkerStatusManagerRefreshPeriodMsec = 5000;
/*!
 * Etiquette for output.
 */
const std::string kWorkerEtq = "WORKER: ";
const std::string kWorker1Etq = "TEnqueuer: ";
const std::string kWorker2Etq = "StatusManager: ";
}
//-----------------------------------------------------------------------------
// Class definitions
namespace middleware {
/*!
 * Class describing a worker.
 */
class Worker : public Runner {
public:
	/*!
	 * Default constructor. Set to default capabilities address for binding
	 * is specified bu descriptor, while other addresses are initialized to
	 * loopback and non valid port.
	 */
	explicit Worker(WorkerDescriptor descriptor);
	/*!
	 * Specifying capabilities and configuration.
	 */
	Worker(WorkerDescriptor descriptor, WorkerConfig conf);
	/*!
	 * Destructor.
	 */
	~Worker();
	/*!
	 * Runs Worker.
	 */
	void run() {
		this->_worker_thread = boost::shared_ptr<boost::thread>(
				new boost::thread(
						boost::bind(&Worker::exec, this)));
	}
	/*!
	 * Join this thread and wait for it to finish.
	 */
	void join() {
		(this->_worker_thread)->join();
	}
private:
	/*!
	 * Creates a casual port number > 1050 and gets it.
	 */
	std::string createPort();
	/*!
	 * Execution function.
	 */
	void exec();
	/*!
	 * Execution function for enqueuer.
	 */
	void exec_enqueuer();
	/*!
	 * Execution function for status manager.
	 */
	void exec_workerstatus_manager();
	/*!
	 * Manages a task when arriving ==> Executing it.
	 */
	void ManageTask(TaskDescriptor task);
	/*!
	 * Initialization routine with user.
	 */
	void bonjour();
	/*!
	 * Configuration for Discovery.
	 */
	WorkerConfig _config;
	/*!
	 * Capabilities of this worker.
	 */
	WorkerDescriptor _worker_descriptor;
	/*!
	 * Undrlaying thread. Responsible for dequeueing and executing tasks.
	 */
	boost::shared_ptr<boost::thread> _worker_thread;
	/*!
	 * Undrlaying thread. Responsible for enueueing tasks.
	 */
	boost::shared_ptr<boost::thread> _enqueuer_thread;
	/*!
	 * Undrlaying thread. Responsible for sending worker status to discovery.
	 */
	boost::shared_ptr<boost::thread> _workerstatus_manager_thread;
	/*!
	 * Queue of tasks.
	 */
	TaskSynQueue _task_synqueue;
};
} /* middleware */

#endif
